#!/usr/bin/env python
# dEdit.py - a Qt4 Text Editor
version='v0.02'

import sys
from PyQt4 import QtCore, QtGui
from ui_dEdit import Ui_MainWindow
from ui_dEditFind import Ui_findDialog
import rc_dEdit_rc

class findDialog(QtGui.QDialog):
    def __init__(self, parent=None):
        QtGui.QDialog.__init__(self, parent)
        self.ui=Ui_findDialog()
        self.ui.setupUi(self)

    @QtCore.pyqtSignature("")
    def on_closeButton_clicked(self): self.hide()
    @QtCore.pyqtSignature("")
    def on_searchButton_clicked(self): self.findWord()

    def findWord(self):
        self.flags=QtGui.QTextDocument.FindFlag(0)
        if self.ui.backwardCheckBox.checkState():
            self.flags=self.flags|QtGui.QTextDocument.FindFlag(1)
        if self.ui.sensitiveCheckBox.checkState():
            self.flags=self.flags|QtGui.QTextDocument.FindFlag(2)
        if self.ui.wholeCheckBox.checkState():
            self.flags=self.flags|QtGui.QTextDocument.FindFlag(4)

#keep working on this
        if  not mainwindow.activeEditor().find(self.ui.findLineEdit.text(), self.flags):
            mainwindow.mb.warning(self, 'Find', 
                                "<b>'%s'</b> not found. " %self.ui.findLineEdit.text()  +
                                "Do you want to keep searching?")

class EditWindow(QtGui.QTextEdit):
    documentNumber=1

    def __init__(self, parent=None):
        QtGui.QTextEdit.__init__(self, parent)
        self.connect(self, QtCore.SIGNAL("textChanged()"), self.changed)
        font=QtGui.QFont()
        font.setFamily("Bitstream Vera Sans Mono")
        self.setFont(font)

    def changed(self):
        self.setWindowModified(self.document().isModified())
        self.setWindowTitle(self.filename+ ' - modified')

    def sizeHint(self):
        return QtCore.QSize(82 * self.fontMetrics().width('x'),
                            25 * self.fontMetrics().lineSpacing())

    def makeWindowAction(self):
        self.action=QtGui.QAction(mainwindow)
        self.action.setText(self.filename)
        return self.action

    def setCurrentFile(self):
        self.setWindowIcon(QtGui.QIcon(":/graphics/txt.png"))
        self.setWindowTitle(self.filename)
        self.makeWindowAction()

    def fileNew(self):
        self.filename="untitled-%s.txt" % EditWindow.documentNumber
        self.isUntitled=True
        self.setCurrentFile()
        EditWindow.documentNumber+=1

    def fileOpen(self, filepath):
        file=QtCore.QFile(filepath)

        if not file.open(QtCore.QFile.ReadOnly|QtCore.QFile.Text):
            mainwindow.mb.warning(self, "Error", "Cannot read file %s:\n%s."
                                    %(filepath, file.errorString()))
            return False

        self.filename=QtCore.QFileInfo(filepath).fileName()
        app.setOverrideCursor(QtCore.Qt.WaitCursor)
        self.setText(QtCore.QTextStream(file).readAll())
        app.restoreOverrideCursor()
        self.filepath=filepath
        self.isUntitled=False
        self.document().setModified(False)
        self.setWindowModified(False)
        self.setCurrentFile()
        return True

    def ok2continue(self):
        if self.document().isModified():
            ok=mainwindow.mb.question(self, "Save Changes?",
                        "<b>%s</b> has changed, do you want to save it?" % self.filename,
                        mainwindow.mb.Save|mainwindow.mb.Default,
                        mainwindow.mb.Discard,
                        mainwindow.mb.Cancel|mainwindow.mb.Escape)
            if ok==mainwindow.mb.Save: return self.fileSave()
            elif ok==mainwindow.mb.Cancel: return False
        return True

    def fileSave(self):
        if self.isUntitled:
            if not self.fileSaveAs(): return False
        else:
            file=QtCore.QFile(self.filepath)
            if not file.open(QtCore.QFile.WriteOnly|QtCore.QFile.Text):
                mainwindow.mb.warning(self, "Error", "Cannot write file: <b>'%s'</b>\n%s."
                                    %(self.filepath, file.errorString()))
                return False

            self.filename=QtCore.QFileInfo(self.filepath).fileName()
            app.setOverrideCursor(QtCore.Qt.WaitCursor)
            QtCore.QTextStream(file) << self.toPlainText()
            app.restoreOverrideCursor()
            self.document().setModified(False)
            self.setWindowModified(False)
            self.setCurrentFile()
            return True

    def fileSaveAs(self):
        self.filepath=mainwindow.freq.getSaveFileName(self, "Save as")
        if self.filepath.isEmpty(): return False
        else:
            self.isUntitled=False
            return self.fileSave()

    def closeEvent(self, event):
        if self.ok2continue():
            event.accept()
        else: event.ignore()

    def fileFind(self): pass


class MainWindow(QtGui.QMainWindow):
    def __init__(self, fileName=None, parent=None):
        QtGui.QMainWindow.__init__(self, parent)
        self.ui=Ui_MainWindow()
        self.ui.setupUi(self)
        self.workspace=QtGui.QWorkspace(self)
        self.setCentralWidget(self.workspace)

        splash.showMessage("Setting up dialog windows...",
                    QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop, QtCore.Qt.white)
        self.freq=QtGui.QFileDialog()
        self.mb=QtGui.QMessageBox()
        self.finder=findDialog(self)
        self.fileFilters="All files (*)\nPython source (*.py*)\nText files (*.txt)"

        splash.showMessage("Connecting slots and signals...",
                    QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop, QtCore.Qt.white)
        self.winMapper=QtCore.QSignalMapper(self)
        self.connect(self.winMapper, QtCore.SIGNAL("mapped(QWidget *)"),
                    self.workspace, QtCore.SLOT("setActiveWindow(QWidget *)"))
        self.connect(self.workspace, QtCore.SIGNAL("windowActivated(QWidget *)"),
                    self.updateMenus)

# connect callback hooks

        #self.connect(self.finder.ui.on_closeButton_clicked())
        self.connect(self.ui.actionNew, QtCore.SIGNAL("triggered()"), self.fileNew)
        self.connect(self.ui.actionOpen, QtCore.SIGNAL("triggered()"), self.fileOpen)
        self.connect(self.ui.actionSave, QtCore.SIGNAL("triggered()"), self.fileSave)
        self.connect(self.ui.actionSave_as, QtCore.SIGNAL("triggered()"), self.fileSaveAs)
        self.connect(self.ui.actionClose, QtCore.SIGNAL("triggered()"), self.fileClose)
        self.connect(self.ui.actionExit, QtCore.SIGNAL("triggered()"), self.fileExit)
        self.connect(self.ui.actionUndo, QtCore.SIGNAL("triggered()"), self.undo)
        self.connect(self.ui.actionRedo, QtCore.SIGNAL("triggered()"), self.redo)
        self.connect(self.ui.actionCut, QtCore.SIGNAL("triggered()"), self.cut)
        self.connect(self.ui.actionCopy,QtCore.SIGNAL("triggered()"), self.copy)
        self.connect(self.ui.actionPaste, QtCore.SIGNAL("triggered()"), self.paste)
        self.connect(self.ui.actionZoom_in, QtCore.SIGNAL("triggered()"), self.zoomIn)
        self.connect(self.ui.actionZoom_out, QtCore.SIGNAL("triggered()"), self.zoomOut)
        self.connect(self.ui.actionAbout, QtCore.SIGNAL("triggered()"), self.about)
        self.connect(self.ui.actionFind, QtCore.SIGNAL("triggered()"), self.findWord)
        self.connect(self.ui.actionFind_next, QtCore.SIGNAL("triggered()"), self.notyet)
        self.connect(self.ui.actionClose_2, QtCore.SIGNAL("triggered()"),
                    self.workspace.closeActiveWindow)
        self.connect(self.ui.actionClose_all, QtCore.SIGNAL("triggered()"),
                    self.workspace.closeAllWindows)
        self.connect(self.ui.actionTile, QtCore.SIGNAL("triggered()"), self.workspace.tile)
        self.connect(self.ui.actionCascade, QtCore.SIGNAL("triggered()"),
                    self.workspace.cascade)
        self.connect(self.ui.actionNext, QtCore.SIGNAL("triggered()"),
                    self.workspace.activateNextWindow)
        self.connect(self.ui.actionPrevious, QtCore.SIGNAL("triggered()"),
                    self.workspace.activatePreviousWindow)
        self.connect(self.ui.menuWindow, QtCore.SIGNAL("aboutToShow()"),
                    self.updateWindowMenu)

        self.updateMenus()
        splash.showMessage("Ready...",
                    QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop, QtCore.Qt.white)

    def fileNew(self):
        editor=self.createEditor()
        editor.fileNew()
        editor.showMaximized()

    def createEditor(self):
        editor=EditWindow()
        self.connect(editor, QtCore.SIGNAL("copyAvailable(bool)"),
                    self.ui.actionCut.setEnabled)
        self.connect(editor, QtCore.SIGNAL("copyAvailable(bool)"),
                    self.ui.actionCopy.setEnabled)
        self.workspace.addWindow(editor)
        self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
        return editor

    def activeEditor(self):
        return self.workspace.activeWindow()

    def findEditor(self, filename):
        found=QtCore.QFileInfo(filename).canonicalFilePath()

        for win in self.workspace.windowList():
            if found==win.filename:
                return win
        return None

    def fileOpen(self):
        filepath=self.freq.getOpenFileName(self, 'Open', '.', self.fileFilters)
        if filepath.isNull(): return
        if not filepath.isEmpty():
            alreadyOpen=self.findEditor(filepath)
            if alreadyOpen:
                self.workspace.setActiveWindow(alreadyOpen)
                return

        editor=self.createEditor()
        if editor.fileOpen(filepath):
            self.statusBar().showMessage("File loaded", 2000)
            editor.showMaximized()
        else: editor.close()

    def fileSave(self):
        if self.activeEditor().fileSave():
            self.statusBar().showMessage("File saved", 2000)

    def fileSaveAs(self):
        if self.activeEditor().fileSaveAs():
            self.statusBar().showMessage("File saved", 2000)

    def fileClose(self): self.activeEditor().close()

    def closeEvent(self, event):
        self.workspace.closeAllWindows()
        if self.activeEditor():
            event.ignore()
        else:
            event.accept()

    def undo(self): self.activeEditor().undo()
    def redo(self): self.activeEditor().redo()
    def cut(self): self.activeEditor().cut()
    def copy(self): self.activeEditor().copy()
    def paste(self): self.activeEditor().paste()
    def zoomIn(self): self.activeEditor().zoomIn(1)
    def zoomOut(self): self.activeEditor().zoomOut(1)

    def fileExit(self):
        if self.activeEditor().ok2continue(): app.quit()

    def findWord(self):
        #self.workspace.addWindow(self.finder)
        self.finder.show()
        #return(self.finder.exec_())

    def about(self):
        self.mb.about(self, "About dEdit",
"""
<h2>dEdit %s</h2>
<p>&copy;2007, David J Brooks
<p><a href="mailto:daeg@houston.rr.com">d&aelig;g@houston.rr.com</a>
<p>All rights reserved.
""" %version)

    def notyet(self):
        self.mb.about(self, "Not yet implimented",
"""
<h2>Under Construction</h2>
<p>The feature you are trying to use
<p>has not been implimented yet.<p>
""")

    def updateMenus(self):
        hasEditor=(self.activeEditor() is not None)
        self.ui.actionSave.setEnabled(hasEditor)
        self.ui.actionSave_as.setEnabled(hasEditor)
        self.ui.actionPaste.setEnabled(hasEditor)
        self.ui.actionClose.setEnabled(hasEditor)
        self.ui.actionClose_2.setEnabled(hasEditor)
        self.ui.actionClose_all.setEnabled(hasEditor)
        self.ui.actionTile.setEnabled(hasEditor)
        self.ui.actionCascade.setEnabled(hasEditor)
        self.ui.actionNext.setEnabled(hasEditor)
        self.ui.actionPrevious.setEnabled(hasEditor)
        self.ui.actionUndo.setEnabled(hasEditor)
        self.ui.actionRedo.setEnabled(hasEditor)
        self.ui.actionZoom_in.setEnabled(hasEditor)
        self.ui.actionZoom_out.setEnabled(hasEditor)
        self.ui.actionFind.setEnabled(hasEditor)

        hasSelection=(self.activeEditor() is not None and self.activeEditor().textCursor().hasSelection())
        self.ui.actionCut.setEnabled(hasSelection)
        self.ui.actionCopy.setEnabled(hasSelection)

    def updateWindowMenu(self):
        self.ui.menuWindow.clear()
        self.ui.menuWindow.addAction(self.ui.actionClose_2)
        self.ui.menuWindow.addAction(self.ui.actionClose_all)
        self.ui.menuWindow.addSeparator()
        self.ui.menuWindow.addAction(self.ui.actionTile)
        self.ui.menuWindow.addAction(self.ui.actionCascade)
        self.ui.menuWindow.addSeparator()
        self.ui.menuWindow.addAction(self.ui.actionNext)
        self.ui.menuWindow.addAction(self.ui.actionPrevious)

        if self.activeEditor():
            self.ui.menuWindow.addSeparator()
        windows=self.workspace.windowList()
        numVisibleEditors=0

        for win in windows:
            text=QtCore.QString("%s %s" %(numVisibleEditors + 1,win.filename))
            if numVisibleEditors < 9:
                text.prepend("&")
            numVisibleEditors+=1

            action=self.ui.menuWindow.addAction(text)
            action.setCheckable(True)
            action.setChecked(win==self.activeEditor())

            self.connect(action, QtCore.SIGNAL("triggered()"),
                        self.winMapper, QtCore.SLOT("map()"))
            self.winMapper.setMapping(action, win)


if __name__=="__main__":
    app=QtGui.QApplication(sys.argv)
    splash=QtGui.QSplashScreen()
    splash.setPixmap(QtGui.QPixmap(":/graphics/dEdit.png"))
    splash.show()
    splash.showMessage("Setting up main window...",
                    QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop, QtCore.Qt.white)
    mainwindow=MainWindow()
    mainwindow.show()
    splash.finish(mainwindow)
    sys.exit(app.exec_())
